package com.example.bus.google.config;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author guoQ.z
 * @date 2021/3/3
 * 注册事件消费者逻辑到事件总线
 * 该方式和非Spring应用中注册事件消费者逻辑到事件总线的方式也有很大不同，这里通过注解@Component定义了一个bean，并且他实现了Spring的接口BeanPostProcessor。利用这种方式，Spring IoC首先会在容器中定义了一个bean eventSubscribeBeanPostProcessor，然后在容器实例化其他每个bean时，会对该bean调用eventSubscribeBeanPostProcessor bean的方法postProcessAfterInitialization(),这样，我们就有一个机会来检测每个bean是否是一个Guava @Subscribe定义的事件监听器bean，如果是，我们就可将该bean注册到事件总线bean eventBus上。
 * ————————————————
 * 版权声明：本文为CSDN博主「安迪源文」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
 * 原文链接：https://blog.csdn.net/andy_zhang2007/article/details/79143213
 */
@Component
public class EventSubscribeBeanPostProcess implements BeanPostProcessor {

    @Autowired
    private EventBus eventBus;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * //对于每个容器执行了初始化的 bean，如果这个 bean 的某个方法注解了@Subscribe,则将该 bean 注册到事件总线
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Method[] methods = bean.getClass().getMethods();
        for (Method method : methods) {
            Subscribe annotation = method.getAnnotation(Subscribe.class);

            // 如果这是一个Guava @Subscribe注解的事件监听器方法，说明所在bean实例
            // 对应一个Guava事件监听器类，将该bean实例注册到Guava事件总线

            if (!Objects.isNull(annotation)) {
                eventBus.register(bean);
                return bean;
            }
        }
        return bean;
    }
}
